package com.insight.modules.system.controller;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import com.insight.common.api.vo.Result;
import com.insight.common.constant.CommonConstant;
import com.insight.common.constant.CommonSendStatus;
import com.insight.common.message.websocket.WebSocket;
import com.insight.common.message.webssh.pojo.WebsocketConst;
import com.insight.common.mq.RedisMq;
import com.insight.common.mq.stream.Streams;
import com.insight.common.system.query.QueryGenerator;
import com.insight.common.system.util.JwtUtil;
import com.insight.common.system.vo.LoginUser;
import com.insight.common.util.oConvertUtils;
import com.insight.modules.system.entity.SysAnnouncement;
import com.insight.modules.system.entity.SysUsers;
import com.insight.modules.system.service.ISysAnnouncementSendService;
import com.insight.modules.system.service.ISysAnnouncementService;
import com.insight.modules.system.service.ISysUserService;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 系统通告表控制器
 * <p>
 * 提供系统通告的增删改查、发布撤销、用户消息获取及导入导出功能。
 * </p>
 *
 * @author jeecg-boot
 * @date 2019-01-02
 * @version V1.0
 */
@RestController
@RequestMapping("/sys/annountCement")
@Slf4j
public class SysAnnouncementController {

    // 注入系统通告服务，用于操作系统通告数据
    @Autowired
    private ISysAnnouncementService sysAnnouncementService;

    // 注入系统通告发送服务，用于发送通知消息
    @Autowired
    private ISysAnnouncementSendService sysAnnouncementSendService;

    // 注入用户服务，用于查询用户相关信息
    @Autowired
    private ISysUserService sysUserService;

    // 注入Redis消息队列工具，用于消息推送
    @Autowired
    private RedisMq redisMq;

    /**
     * 分页查询系统通告列表
     *
     * @param sysAnnouncement 查询条件实体，支持模糊查询标题
     * @param pageNo          当前页码，默认1
     * @param pageSize        每页显示数量，默认10
     * @param req             HttpServletRequest，获取排序字段及方向等参数
     * @return Result封装的分页结果集，包括数据列表和分页信息
     */
    @GetMapping("/list")
    public Result<IPage<SysAnnouncement>> queryPageList(SysAnnouncement sysAnnouncement,
                                                        @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                                        @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
                                                        HttpServletRequest req) {
        Result<IPage<SysAnnouncement>> result = new Result<>();
        QueryWrapper<SysAnnouncement> queryWrapper = new QueryWrapper<>();

        // 标题模糊匹配条件
        if (StringUtils.isNotBlank(sysAnnouncement.getTitile())) {
            queryWrapper.like("titile", sysAnnouncement.getTitile());
        }
        // 只查询未逻辑删除的数据（del_flag=0）
        queryWrapper.eq("del_flag", CommonConstant.DEL_FLAG_0.toString());

        // 创建分页对象，传入页码和每页大小
        Page<SysAnnouncement> page = new Page<>(pageNo, pageSize);

        // 获取排序字段和排序方式，支持前端传入参数动态排序
        String column = req.getParameter("column");
        String order = req.getParameter("order");
        if (oConvertUtils.isNotEmpty(column) && oConvertUtils.isNotEmpty(order)) {
            if ("asc".equalsIgnoreCase(order)) {
                queryWrapper.orderByAsc(oConvertUtils.camelToUnderline(column));
            } else {
                queryWrapper.orderByDesc(oConvertUtils.camelToUnderline(column));
            }
        }

        // 执行分页查询
        IPage<SysAnnouncement> pageList = sysAnnouncementService.page(page, queryWrapper);

        // 记录分页查询日志，方便排查
        log.info("查询当前页：" + pageList.getCurrent());
        log.info("查询当前页数量：" + pageList.getSize());
        log.info("查询结果数量：" + pageList.getRecords().size());
        log.info("数据总数：" + pageList.getTotal());

        // 返回结果，标记成功并携带数据
        result.setSuccess(true);
        result.setResult(pageList);
        return result;
    }

    /**
     * 新增系统通告
     *
     * @param sysAnnouncement 前端传入的通告实体对象，包含标题、内容等信息
     * @return 结果对象，成功或失败提示
     */
    @PostMapping("/add")
    public Result<SysAnnouncement> add(@RequestBody SysAnnouncement sysAnnouncement) {
        Result<SysAnnouncement> result = new Result<>();
        try {
            if (sysAnnouncement == null) {
                return result.error500("请求参数为空");
            }
            sysAnnouncement.setDelFlag(CommonConstant.DEL_FLAG_0.toString());
            sysAnnouncement.setSendStatus(CommonSendStatus.UNPUBLISHED_STATUS_0);
            sysAnnouncementService.saveAnnouncement(sysAnnouncement);
            result.success("添加成功！");
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            result.error500("操作失败");
        }
        return result;
    }

    /**
     * 编辑系统通告
     *
     * @param sysAnnouncement 包含ID及修改后的通告信息
     * @return 结果对象，包含成功或失败状态
     */
    @PutMapping("/edit")
    public Result<SysAnnouncement> edit(@RequestBody SysAnnouncement sysAnnouncement) {
        Result<SysAnnouncement> result = new Result<>();
        // 根据ID查询已有实体，判断是否存在
        SysAnnouncement sysAnnouncementEntity = sysAnnouncementService.getById(sysAnnouncement.getId());
        if (sysAnnouncementEntity == null) {
            // 不存在则返回错误信息
            result.error500("未找到对应实体");
        } else {
            // 调用更新接口，返回boolean标识更新结果
            boolean ok = sysAnnouncementService.upDateAnnouncement(sysAnnouncement);
            if (ok) {
                // 更新成功返回
                result.success("修改成功!");
            }
        }
        return result;
    }

    /**
     * 通过ID逻辑删除系统通告
     *
     * @param id 通告ID
     * @return 结果对象，包含删除是否成功状态
     */
    @DeleteMapping("/delete")
    public Result<SysAnnouncement> delete(@RequestParam(name = "id", required = true) String id) {
        Result<SysAnnouncement> result = new Result<>();
        // 查询实体是否存在
        SysAnnouncement sysAnnouncement = sysAnnouncementService.getById(id);
        if (sysAnnouncement == null) {
            result.error500("未找到对应实体");
        } else {
            // 设置逻辑删除标记为已删除
            sysAnnouncement.setDelFlag(CommonConstant.DEL_FLAG_1.toString());
            // 调用更新方法保存删除状态
            boolean ok = sysAnnouncementService.updateById(sysAnnouncement);
            if (ok) {
                // 删除成功返回
                result.success("删除成功!");
            }
        }
        return result;
    }

    /**
     * 批量删除系统通告（逻辑删除）
     *
     * @param ids 逗号分隔的通告ID字符串
     * @return 操作结果，成功或失败提示
     */
    @DeleteMapping("/deleteBatch")
    public Result<Object> deleteBatch(@RequestParam(name = "ids") String ids) {
        // 调用服务层批量删除接口
        Boolean success = sysAnnouncementService.removeAnnouncement(ids);
        if (success) {
            return Result.OK("删除成功!");
        } else {
            return Result.error500("删除失败,无法删除已发布通知");
        }
    }

    /**
     * 通过ID查询系统通告详情
     *
     * @param id 通告ID
     * @return 结果封装，成功包含通告数据，失败返回错误提示
     */
    @GetMapping("/queryById")
    public Result<SysAnnouncement> queryById(@RequestParam(name = "id", required = true) String id) {
        Result<SysAnnouncement> result = new Result<>();
        SysAnnouncement sysAnnouncement = sysAnnouncementService.getById(id);
        if (sysAnnouncement == null) {
            result.error500("未找到对应实体");
        } else {
            result.setSuccess(true);
            result.setResult(sysAnnouncement);
        }
        return result;
    }

    /**
     * 发布系统通告，更新状态并发送通知消息
     *
     * @param id      通告ID
     * @param request HttpServletRequest，用于获取当前登录用户信息
     * @return 操作结果封装
     */
    @GetMapping("/doReleaseData")
    public Result<SysAnnouncement> doReleaseData(@RequestParam(name = "id", required = true) String id, HttpServletRequest request) {
        Result<SysAnnouncement> result = new Result<>();
        // 查询通告是否存在
        SysAnnouncement sysAnnouncement = sysAnnouncementService.getById(id);
        if (sysAnnouncement == null) {
            result.error500("未找到对应实体");
        } else {
            // 设置发布状态为已发布
            sysAnnouncement.setSendStatus(CommonSendStatus.PUBLISHED_STATUS_1);
            // 设置发布时间为当前时间
            sysAnnouncement.setSendTime(new Date());
            // 通过token获取当前用户名，记录发布人
            String currentUserName = JwtUtil.getUserNameByToken(request);
            sysAnnouncement.setSender(currentUserName);
            // 获取登录用户的真实姓名，便于前端显示
            String loginUser = com.yuanqiao.insight.common.core.util.SecurityUtils.getUser().getRealname();
            sysAnnouncement.setSender_dictText(loginUser);

            // 更新数据库状态
            boolean ok = sysAnnouncementService.updateById(sysAnnouncement);
            if (ok) {
                // 调用发送服务广播消息给前端
                sysAnnouncementSendService.senderMsg(id, "notice", sysAnnouncement);
                result.success("该系统通知发布成功");
            }
        }
        return result;
    }

    /**
     * 撤销发布系统通告，设置状态为撤销并发送撤销通知
     *
     * @param id 通告ID
     * @return 操作结果封装
     */
    @GetMapping("/doReovkeData")
    public Result<SysAnnouncement> doReovkeData(@RequestParam(name = "id", required = true) String id) {
        Result<SysAnnouncement> result = new Result<>();
        // 查询通告是否存在
        SysAnnouncement sysAnnouncement = sysAnnouncementService.getById(id);
        if (sysAnnouncement == null) {
            result.error500("未找到对应实体");
        } else {
            // 设置状态为撤销
            sysAnnouncement.setSendStatus(CommonSendStatus.REVOKE_STATUS_2);
            // 设置撤销时间为当前时间
            sysAnnouncement.setCancelTime(new Date());

            // 更新数据库
            boolean ok = sysAnnouncementService.updateById(sysAnnouncement);
            if (ok) {
                // 构造撤销消息数据体
                JSONObject data = new JSONObject();
                data.put("id", id);
                data.put("msgCategory", sysAnnouncement.getMsgCategory());
                // 发送撤销通知消息给前端
                sysAnnouncementSendService.senderMsg(id, "clearNotice", data);
                result.success("该系统通知撤销成功");
            }
        }
        return result;
    }

    /**
     * 获取当前登录用户的系统消息及通知公告，默认只返回前5条
     *
     * @return 包含用户消息列表及总数的结果封装
     */
    @GetMapping("/listByUser")
    public Result<Map<String, Object>> listByUser() {
        Result<Map<String, Object>> result = new Result<>();
        // 获取当前登录用户信息
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        String userId = sysUser.getId();

        // 查询该用户收到的公告消息，分页只取前5条
        Page<SysAnnouncement> anntMsgList = sysAnnouncementService.querySysCementPageByUserId(new Page<>(0, 5), userId, "1");
        // 查询该用户收到的系统消息，分页只取前5条
        Page<SysAnnouncement> sysMsgList = sysAnnouncementService.querySysCementPageByUserId(new Page<>(0, 5), userId, "2");

        // 设置消息发送者的真实姓名，方便显示
        anntMsgList.getRecords().forEach(item -> {
            final SysUsers user = sysUserService.getOne(new LambdaQueryWrapper<SysUsers>().eq(SysUsers::getUsername, item.getSender()));
            if (user != null) item.setSender_dictText(user.getRealname());
        });
        sysMsgList.getRecords().forEach(item -> {
            final SysUsers user = sysUserService.getOne(new LambdaQueryWrapper<SysUsers>().eq(SysUsers::getUsername, item.getSender()));
            if (user != null) item.setSender_dictText(user.getRealname());
        });

        // 构建返回数据结构，包括列表及总数
        Map<String, Object> sysMsgMap = new HashMap<>();
        sysMsgMap.put("sysMsgList", sysMsgList.getRecords());
        sysMsgMap.put("sysMsgTotal", sysMsgList.getTotal());
        sysMsgMap.put("anntMsgList", anntMsgList.getRecords());
        sysMsgMap.put("anntMsgTotal", anntMsgList.getTotal());

        // 返回结果
        result.setSuccess(true);
        result.setResult(sysMsgMap);
        return result;
    }

    /**
     * 导出系统通告数据为Excel文件
     *
     * @param sysAnnouncement 查询过滤条件
     * @param request         HttpServletRequest，获取请求参数
     * @return 导出视图对象，触发Excel文件下载
     */
    @RequestMapping("/exportXls")
    public ModelAndView exportXls(SysAnnouncement sysAnnouncement, HttpServletRequest request) {
        // 根据条件构建查询Wrapper，过滤未逻辑删除的记录
        QueryWrapper<SysAnnouncement> queryWrapper = QueryGenerator.initQueryWrapper(sysAnnouncement, request.getParameterMap());
        queryWrapper.eq("del_flag", CommonConstant.DEL_FLAG_0.toString());

        // 查询符合条件的列表
        List<SysAnnouncement> pageList = sysAnnouncementService.list(queryWrapper);
        // 创建Excel导出视图
        ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
        // 获取当前登录用户信息，用于Excel文件的导出人字段
        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();

        // 设置导出文件名
        mv.addObject(NormalExcelConstants.FILE_NAME, "系统通告列表");
        // 设置导出实体类
        mv.addObject(NormalExcelConstants.CLASS, SysAnnouncement.class);
        // 设置导出参数（标题和导出人）
        mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("系统通告列表数据", "导出人:" + user.getRealname(), "导出信息"));
        // 设置数据列表
        mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
        return mv;
    }

    /**
     * Excel文件导入系统通告数据
     *
     * @param request  HTTP请求，获取上传文件
     * @param response HTTP响应
     * @return 导入结果提示
     */
    @PostMapping("/importExcel")
    public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
        for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
            MultipartFile file = entity.getValue();
            ImportParams params = new ImportParams();
            params.setTitleRows(2); // 标题占2行
            params.setHeadRows(1);  // 表头占1行
            params.setNeedSave(true); // 是否保存上传文件


